__all__ = ("add","calc")
class Ammo:
    __slots__ = ("f", "t", "n")
    def __init__(self, typ, fro=None, to=None):
        self.f, self.t, self.n = fro, to, typ
class Mag(list):
    def remove(self, player):
        for index, ammo in list(enumerate(self)):
            if ammo.f == player and ammo.n != 3:
                self.pop(index)
    def n(self):
        return sum([i.n for i in self])
class Player:
    __slots__ = ("name","operation","target","target_ammo",
                 "att_ammo","att_player","die","alive")
    def __init__(self, name, operation):
        self.name = name
        self.operation, self.target = operation
        self.target_ammo, self.att_ammo = Mag(), Mag()
        self.att_player = list()
        self.die, self.alive = False, False
    def lost(self):
        self.die = True
    def win(self):
        self.alive = True
    def __str__(self):
        return self.name
    def __bool__(self):
        return self.alive or not self.die
class Game:
    chart = {(1,1): 3, (1,2): 1, (2,1): 2, (2,2): 3}
    def __init__(self):
        self.turns = int()
        self.players = list()
        self.result = dict()
    def add_player(self, name, operation):
        if operation != [-1,0]:
            self.players.append(Player(name, operation))
        self.result[name] = operation
    def output(self, turn):
        self.turns = turn
        n2p = {i.name : i for i in self.players}
        for i in self.players:
            for target_name, ammo in i.target.items():
                if target_name not in n2p:continue
                target = n2p[target_name]
                target.att_ammo.append(Ammo(ammo, i, target))
                target.att_player.append(i)
                if i.name in target.target and target_name != i.name:
                    target.target_ammo.append(Ammo(target.target[i.name], target, i))
                    if target_name in target.target:
                        i.target_ammo.append(Ammo(target.target[target_name],target,target))
        for i, p in [(i.att_ammo.n(),i) for i in self.players if i.att_ammo.n() == 3]:
            for player in p.att_player:
                if p is not player:
                    player.att_ammo.remove(p)
            p.lost()
        for i in self.players:
            match i.att_ammo.n():
                case 4:
                    self.lost(i.att_player)
                    i.win()
                case 5:
                    self.lost(set(self.players)-set(i.att_player))
                    self.win(i.att_player)
                case 6 | 7 | 8 | 9:
                    return {a: b+[2] for a,b in self.result.items()},True
                case a if a >= 10:
                    return {a: b+[1] for a,b in self.result.items()},False
                case b if b > 1 or (b==1 and i.operation!=1):
                    if i.target_ammo.n() == 0:i.lost()
                    if i.operation == 1:i.att_ammo.append(Ammo(-1, fro=i))
                    result = self.chart.get((i.target_ammo.n(),b))
                    if result == 1:
                        self.lost(set(i.att_player)-{i,})
                    elif result == 2:
                        i.lost()
                    elif result == 3:
                        self.lost(set(i.att_player)-{i,})
                        i.lost()
        statu = len(list(filter(None, self.players))) < 2
        result = {a : b+[3 if n2p.get(a) else 2] for a,b in self.result.items()}\
            if statu else {a : b+[1 if n2p.get(a) else 0] for a,b in self.result.items()}
        self.result = dict()
        self.players = list()
        return result, statu
    @staticmethod
    def lost(players):
        return [i.lost() for i in players]
    @staticmethod
    def win(players):
        return [i.win() for i in players]
game = Game()
def add(name:str, operation:list[int, dict]) -> None:
    return game.add_player(name, operation)
def calc(turns:int = 0) -> tuple[dict, bool]:
    return game.output(turns)